package com.supplychain.scm.core.http.client.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.supplychain.scm.core.basis.constant.StringPool;
import com.supplychain.scm.core.common.util.SpringContextHolder;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName OkHttpUtil
 * @Description OKHTTP工具类
 * @createTime 15:49:00 2022/05/10
 */
@Slf4j
@UtilityClass
public class OkHttpUtil {

    /**
     * 根据map获取get请求参数
     *
     * @param queries params
     * @return StringBuffer
     */
    public StringBuffer getQueryString(String url, Map<String, String> queries) {
        StringBuffer sb = new StringBuffer(url);
        if (Objects.nonNull(queries) && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            for (Map.Entry<String, String> entry : queries.entrySet()) {
                if (firstFlag) {
                    sb.append(StringPool.QUESTION_MARK).append(entry.getKey()).append(StringPool.EQUALS).append(entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append(StringPool.AMPERSAND).append(entry.getKey()).append(StringPool.EQUALS).append(entry.getValue());
                }
            }
        }
        return sb;
    }

    public StringBuffer getQueryStr(String url, Map<String, Object> queries) {
        StringBuffer sb = new StringBuffer(url);
        if (Objects.nonNull(queries) && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            for (Map.Entry<String, Object> entry : queries.entrySet()) {
                if (firstFlag) {
                    sb.append(StringPool.QUESTION_MARK).append(entry.getKey()).append(StringPool.EQUALS).append(entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append(StringPool.AMPERSAND).append(entry.getKey()).append(StringPool.EQUALS).append(entry.getValue());
                }
            }
        }
        return sb;
    }

    /**
     * 调用okhttp的newCall方法
     *
     * @param request request
     * @return String
     */
    private String execNewCall(Request request, String charset) {
        Response response = null;
        try {
            OkHttpClient okHttpClient = SpringContextHolder.getBean(OkHttpClient.class);
            Assert.notNull(okHttpClient,"ok http client not null");
            response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return StringUtils.isBlank(charset) ? Objects.requireNonNull(response.body()).string() : new String(response.body().bytes(),charset);
            }
        } catch (Exception e) {
            log.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (Objects.nonNull(response)) {
                response.close();
            }
        }
        return "";
    }

    private String execNewCall(Request request,String charset,String proxyHost,Integer proxyPort) {
        Response response = null;
        try {
            Proxy proxy = null;
            if(StringUtils.isNotBlank(proxyHost) && Objects.nonNull(proxyPort)) {
                proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(proxyHost, proxyPort));
            }
            OkHttpClient okHttpClient = SpringContextHolder.getBean(OkHttpClient.class);
            if(Objects.nonNull(proxy)) {
                okHttpClient = okHttpClient.newBuilder().proxy(proxy).build();
            }
            Assert.notNull(okHttpClient,"ok http client not null");
            response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return StringUtils.isBlank(charset) ? Objects.requireNonNull(response.body()).string() : new String(response.body().bytes(),charset);
            }
        } catch (Exception e) {
            log.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (Objects.nonNull(response)) {
                response.close();
            }
        }
        return "";
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return String
     */
    public <T> T get(String url, Map<String, String> queries, TypeReference<T> tTypeReference) {

        return get(url,queries,tTypeReference,null);
    }

    public <T> T get(String url, Map<String, String> queries, TypeReference<T> tTypeReference,String charset) {
        StringBuffer sb = getQueryString(url, queries);
        Request request = new Request.Builder()
                .url(sb.toString())
                .build();
        return JSONObject.parseObject(execNewCall(request,charset), tTypeReference);
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return String
     */
    public String get(String url, Map<String, String> queries) {
        StringBuffer sb = getQueryString(url, queries);
        Request request = new Request.Builder()
                .url(sb.toString())
                .build();
        return execNewCall(request,null);
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return String
     */
    public String get(String url, Map<String, String> queries, Headers headers) {
        StringBuffer sb = getQueryString(url, queries);
        Request request = new Request.Builder()
                .url(sb.toString())
                .headers(headers)
                .build();
        return execNewCall(request,null);
    }

    public String get(String url, Map<String, Object> queries, Headers headers,String proxyHost,Integer proxyPort) {
        StringBuffer sb = getQueryStr(url, queries);
        Request request = new Request.Builder()
                .url(sb.toString())
                .headers(headers)
                .build();
        if(StringUtils.isNotBlank(proxyHost) && Objects.nonNull(proxyPort)) {
            return execNewCall(request,null,proxyHost,proxyPort);
        } else {
            return execNewCall(request,null);
        }
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return String
     */
    public <T> T get(String url, Map<String, String> queries,Headers headers,TypeReference<T> tTypeReference) {
        StringBuffer sb = getQueryString(url, queries);
        Request request = new Request.Builder()
                .url(sb.toString())
                .headers(headers)
                .build();
        return JSONObject.parseObject(execNewCall(request,null), tTypeReference);
    }



    public String postFormParams(String url, Map<String, String> params,boolean retryOnConnectionFailure) throws IOException {
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (Objects.nonNull(params) && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        Response response = null;
        try {
            OkHttpClient okHttpClient = SpringContextHolder.getBean(OkHttpClient.class);
            Assert.notNull(okHttpClient,"ok http client not null");
            response = okHttpClient.newBuilder().retryOnConnectionFailure(retryOnConnectionFailure).build().newCall(request).execute();
            return new String(Objects.requireNonNull(response.body()).bytes(), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
            throw e;
        } finally {
            if (Objects.nonNull(response)) {
                response.close();
            }
        }
    }

    /**
     * post
     *
     * @param url    请求的url
     * @param params post form 提交的参数
     * @return String
     */
    public String postFormParams(String url, Map<String, String> params) {

        return postFormParams(url,params, StringPool.EMPTY);
    }

    public <T> T postFormParams(String url, Map<String, String> params, TypeReference<T> tTypeReference) {

        return JSON.parseObject(postFormParams(url,params, StringPool.EMPTY),tTypeReference);
    }

    public String postFormParams(String url, Map<String, String> params,String charset) {
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (Objects.nonNull(params) && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                //.headers(Headers.of("Content-type","application/x-www-form-urlencoded"))
                .build();
        return execNewCall(request,charset);
    }

	/**
	 * post
	 *
	 * @param url     请求的url
	 * @param params  post form 提交的参数
	 * @param headers 请求头
	 * @return String
	 */
	public String postFormParams(String url, Map<String, String> params,Headers headers) {
		FormBody.Builder builder = new FormBody.Builder();
		//添加参数
		if (Objects.nonNull(params) && params.keySet().size() > 0) {
			for (String key : params.keySet()) {
				builder.add(key, params.get(key));
			}
		}
		Request request = new Request.Builder()
				.url(url)
				.post(builder.build())
				.headers(headers)
				.build();
		return execNewCall(request,null);
	}

    public String postFormParams(String url, Map<String, String> params,Headers headers,String proxyHost,Integer proxyPort) {
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (Objects.nonNull(params) && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .headers(headers)
                .build();
        if(StringUtils.isNotBlank(proxyHost) && Objects.nonNull(proxyPort)) {
            return execNewCall(request,null,proxyHost,proxyPort);
        } else {
            return execNewCall(request,null);
        }
    }

    /**
     * Post请求发送JSON数据....{"name":"zhangsan","pwd":"123456"}
     * 参数一：请求Url
     * 参数二：请求的JSON
     * 参数三：请求回调
     */
    public String postJsonParams(String url, String jsonParams) {
        RequestBody requestBody = RequestBody.create(jsonParams, MediaType.parse("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return execNewCall(request,null);
    }

    public String postJsonParams(String url, String jsonParams,Headers headers) {
        RequestBody requestBody = RequestBody.create(jsonParams, MediaType.parse("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .headers(headers)
                .build();
        return execNewCall(request,null);
    }

    public String postJsonParams(String url, String jsonParams,Headers headers,String proxyHost,Integer proxyPort) {
        RequestBody requestBody = RequestBody.create(jsonParams, MediaType.parse("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .headers(headers)
                .build();
        if(StringUtils.isNotBlank(proxyHost) && Objects.nonNull(proxyPort)) {
            return execNewCall(request,null,proxyHost,proxyPort);
        } else {
            return execNewCall(request,null);
        }
    }

    public String postJsonParams(String url, String jsonParams,String proxyHost,Integer proxyPort) {
        RequestBody requestBody = RequestBody.create(jsonParams, MediaType.parse("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        if(StringUtils.isNotBlank(proxyHost) && Objects.nonNull(proxyPort)) {
            return execNewCall(request,null,proxyHost,proxyPort);
        } else {
            return execNewCall(request,null);
        }
    }

    public <T> T postJsonParams(String url, String jsonParams,TypeReference<T> tTypeReference) {
        String json = postJsonParams(url, jsonParams);
        if(log.isDebugEnabled()) {
            log.debug("okhttp postJsonParams json = {}", json);
        }
        return JSON.parseObject(json, tTypeReference);
    }

    public <T> T postJsonParams(String url, String jsonParams,TypeReference<T> tTypeReference,String proxyHost,Integer proxyPort) {
        String json = postJsonParams(url, jsonParams, proxyHost, proxyPort);
        if(log.isDebugEnabled()) {
            log.debug("okhttp postJsonParams json = {}", json);
        }
        return JSON.parseObject(json, tTypeReference);
    }

    /**
     * Post请求发送xml数据....
     * 参数一：请求Url
     * 参数二：请求的xmlString
     * 参数三：请求回调
     */
    public String postXmlParams(String url, String xml) {
        RequestBody requestBody = RequestBody.create(xml, MediaType.parse("application/xml; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return execNewCall(request,null);
    }

    /**
     * post 上传文件
     *
     * @param url
     * @param params
     * @param fileType
     * @return
     */
    public String postFile(String url, Map<String, Object> params, String fileType) {
        String responseBody = StringPool.EMPTY;
        MultipartBody.Builder builder = new MultipartBody.Builder();
        //添加参数
        if (Objects.nonNull(params) && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                if (params.get(key) instanceof File) {
                    File file = (File) params.get(key);
                    builder.addFormDataPart(key, file.getName(), RequestBody.create(file, MediaType.parse(fileType)));
                    continue;
                }
                builder.addFormDataPart(key, params.get(key).toString());
            }
        }
        Request request = new Request
                .Builder()
                .url(url)
                .post(builder.build())
                .build();
        Response response = null;
        try {
            OkHttpClient okHttpClient = SpringContextHolder.getBean(OkHttpClient.class);
            Assert.notNull(okHttpClient,"ok http client not null");
            response = okHttpClient.newCall(request).execute();
            int status = response.code();
            if (status == HttpStatus.OK.value()) {
                return String.valueOf(response.body());
            }
        } catch (Exception e) {
            log.error("okhttp postFile error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (Objects.nonNull(response)) {
                response.close();
            }
        }
        return responseBody;
    }
}
